/* Yet Another Experimental Software Renderer
 *
 * Copyright (c) 2010 Pawel "Hery" Dziepak
 */

#include <stdio.h>
#include "bmp_files.h"
#include "bmp_output.h"

using namespace yaesr;

bmp_output::bmp_output(const std::string &fname, int w, int h) :
	pixel_output(w, h),
	filename(fname),
	output_buffer(new u32[w * h]) {}

void bmp_output::flush() {
	FILE *fp = NULL;
	fopen_s(&fp, filename.c_str(), "w");

	int bpp = 3;
	int bitmap_size;
	if ((width * bpp) % 4 != 0)
		bitmap_size = (width * bpp + (4 - (width * bpp) % 4)) * height;
	else
		bitmap_size = width * height * bpp;

	bmp_header bhdr;
	bhdr.magic[0] = 0x42;
	bhdr.magic[1] = 0x4d;
	bhdr.file_size = sizeof(bmp_header) + sizeof(dib_header) + bitmap_size;
	bhdr.offset = sizeof(bmp_header) + sizeof(dib_header);
	fwrite(&bhdr, sizeof(bmp_header), 1, fp);

	dib_header dhdr;
	dhdr.header_size = 40;
	dhdr.width = width;
	dhdr.height = height;
	dhdr.planes = 1;
	dhdr.bpp = u16(bpp * 8);
	dhdr.compress_type = 0;
	dhdr.buffer_size = bitmap_size;
	dhdr.hres = 2835;
	dhdr.vres = 2835;
	dhdr.color = 0;
	dhdr.imp_colors = 0;
	fwrite(&dhdr, sizeof(dib_header), 1, fp);

	u8 *bmp_buffer = new u8[bitmap_size];
	memset(bmp_buffer, 0, bitmap_size);

	const int bytes_per_row = bitmap_size / height;
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			u32 color = output_buffer[(height - row - 1) * width + col];
			bmp_buffer[row * bytes_per_row + col * 3] = (u8)color; // blue
			bmp_buffer[row * bytes_per_row + col * 3 + 1] = (u8)(color >> 8); // green
			bmp_buffer[row * bytes_per_row + col * 3 + 2] = (u8)(color >> 16); // red
		}
	}
	fwrite(bmp_buffer, bitmap_size, 1, fp);

	fclose(fp);
}

void bmp_output::write_pixel(int x, int y, color pixel_color) {
	if (x < 0 || x >= width || y < 0 || y >= height) 
		return;

	output_buffer[y * width + x] = pixel_color.to_int32();
}

void bmp_output::clear(color clear_color) {
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			output_buffer[row * width + col] = clear_color.to_int32();
		}
	}
}